#!/usr/bin/python
#encoding=utf-8

from __future__ import print_function

import inspect
import lldb
import optparse
import shlex
import sys
import os
import re

class MapsourceCommand:
    # 命令名称
    program = 'mapsource'
    # 二进制对应版本的本地源码文件路径，eg./Users/admin//lldb_source_cache
    cache_path = os.environ['HOME'] + '/lldb_source_cache'

    @classmethod
    def register_lldb_command(cls, debugger, module_name):
        parser = cls.create_options()
        cls.__doc__ = parser.format_help()
        # Add any commands contained in this module to LLDB
        command = 'command script add -c %s.%s %s' % (module_name, cls.__name__, cls.program)
        debugger.HandleCommand(command)
        print('The "{0}" command has been installed, type "help {0}" for detailed help.'.format(cls.program))

    @classmethod
    def create_options(cls):
        usage = "usage: %prog 0x10413e47c"
        description = ('')
        parser = optparse.OptionParser(
            description=description,
            prog=cls.program,
            usage=usage,
            add_help_option=False)
        return parser

    def get_long_help(self):
        return self.help_string

    def __init__(self, debugger, unused):
        self.parser = self.create_options()
        self.help_string = self.parser.format_help()

    def __call__(self, debugger, command, exe_ctx, result):
        command_args = shlex.split(command)
        try:
            (options, args) = self.parser.parse_args(command_args)
        except:
            result.SetError("option parsing failed")
            return

        interpreter = lldb.debugger.GetCommandInterpreter()
        returnObject = lldb.SBCommandReturnObject()
        interpreter.HandleCommand('image lookup -v --address ' + command, returnObject)
        output = returnObject.GetOutput();

        filePath = re.match(r'(.|\n)*file = "(.*?)".*', output,re.M).group(2)
        fileName = re.match(r'/.*/(.*)', filePath).group(1)
        sourcePath = os.popen('mdfind -onlyin ' + self.cache_path + ' ' +fileName).read().replace('\n','')

        if len(filePath) == 0:
            print('Debuginfo source path:'.ljust(30) + 'No found')
            return
        else:
            print('Debuginfo source path:'.ljust(30) + filePath)


        if len(sourcePath) == 0:
            print('Local source path:'.ljust(30) + 'No found')
            return
        else:
            print('Local source path:'.ljust(30) + sourcePath)

        interpreter.HandleCommand('settings set target.source-map ' + filePath + ' ' + sourcePath, returnObject)


def __lldb_init_module(debugger, dict):
    for _name, cls in inspect.getmembers(sys.modules[__name__]):
        if inspect.isclass(cls) and callable(getattr(cls, "register_lldb_command", None)):
            cls.register_lldb_command(debugger, __name__)